home *** CD-ROM | disk | FTP | other *** search
/ Aminet 24 / Aminet 24 (1998)(GTI - Schatztruhe)[!][Apr 1998].iso / Aminet / comm / mail / Mutt089src.lha / Mutt-0.89i-AMIGA / src / mbox.c < prev    next >
C/C++ Source or Header  |  1998-01-28  |  24KB  |  992 lines

  1. /*
  2.  * Copyright (C) 1996-8 Michael R. Elkins <me@cs.hmc.edu>
  3.  * 
  4.  *     This program is free software; you can redistribute it and/or modify
  5.  *     it under the terms of the GNU General Public License as published by
  6.  *     the Free Software Foundation; either version 2 of the License, or
  7.  *     (at your option) any later version.
  8.  * 
  9.  *     This program is distributed in the hope that it will be useful,
  10.  *     but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.  *     GNU General Public License for more details.
  13.  * 
  14.  *     You should have received a copy of the GNU General Public License
  15.  *     along with this program; if not, write to the Free Software
  16.  *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17.  */ 
  18.  
  19. /* This file contains code to parse ``mbox'' and ``mmdf'' style mailboxes */
  20.  
  21. #include "mutt.h"
  22. #include "mailbox.h"
  23. #include "mx.h"
  24. #include "sort.h"
  25. #include "parse.h"
  26. #include "copy.h"
  27.  
  28. #include <sys/stat.h>
  29. #include <dirent.h>
  30. #include <string.h>
  31. #include <utime.h>
  32. #include <sys/file.h>
  33. #include <errno.h>
  34. #include <unistd.h>
  35. #include <fcntl.h>
  36.  
  37. /* struct used by mutt_sync_mailbox() to store new offsets */
  38. struct m_update_t
  39. {
  40.   long hdr;
  41.   long body;
  42. };
  43.  
  44. #ifdef USE_DOTLOCK
  45. /*
  46.  * Determine whether or not to use a dotlock to lock the indicated file.
  47.  * On some systems, the spool directory is not world-writable.  If it is
  48.  * group-writable, we might need to be setgid() to write the lock.  If not
  49.  * group-writable, then we assume that fcntl() locking is enough and skip
  50.  * the dotlocking.
  51.  *
  52.  * return values:
  53.  *    2    need to be setgid to dotlock
  54.  *    1    can use a dotlock
  55.  *    0    don't use a dotlock
  56.  *    -1    error
  57.  */
  58. static int can_dotlock (const char *path)
  59. {
  60.   char tmp[_POSIX_PATH_MAX];
  61.   char *p;
  62. #ifdef USE_SETGID
  63.   struct stat sb;
  64. #endif
  65.  
  66.   strfcpy (tmp, path, sizeof (tmp));
  67.   if ((p = strrchr (tmp, '/')))
  68.     *p = 0;
  69.   else
  70.     strfcpy (tmp, ".", sizeof (tmp)); /* use current directory */
  71.  
  72.   if (access (tmp, W_OK) == 0) return 1;
  73.  
  74. #ifdef USE_SETGID
  75.   if (stat (tmp, &sb) == 0)
  76.   {
  77.     if ((sb.st_mode & S_IWGRP) == S_IWGRP)
  78.     {
  79.       /* can dotlock, but need to be setgid */
  80.       if (sb.st_gid == MailGid)
  81.     return (2);
  82.       else
  83.       {
  84.     mutt_error ("Need to be running setgid %d to lock mailbox!", sb.st_gid);
  85.     return (-1);
  86.       }
  87.     }
  88.   }
  89. #endif
  90.  
  91.   if (mutt_yesorno ("Can't dotlock mailbox, continue anyway?", 0) == 1)
  92.     return 0;
  93.  
  94.   return (-1);
  95. }
  96. #endif
  97.  
  98. int mbox_lock_mailbox (CONTEXT *ctx, int excl)
  99. {
  100.   int r = 0;
  101.  
  102. #ifdef USE_DOTLOCK
  103.   r = can_dotlock (ctx->path);
  104.  
  105.   if (r == -1)
  106.     return (-1);
  107. #ifdef USE_SETGID
  108.   else if (r == 2)
  109.   {
  110.     /* need to be setgid to lock the mailbox */
  111.     if (SETEGID (MailGid) != 0)
  112.     {
  113.       mutt_perror ("setegid");
  114.       return (-1);
  115.     }
  116.  
  117.     ctx->setgid = 1;
  118.   }
  119. #endif /* USE_SETGID */
  120. #endif /* USE_DOTLOCK */
  121.  
  122.   if ((r = mx_lock_file (ctx->path, fileno (ctx->fp), excl, r)) == 0)
  123.     ctx->locked = 1;
  124.  
  125. #ifdef USE_SETGID
  126.   if (ctx->setgid)
  127.     SETEGID (UserGid);
  128. #endif
  129.  
  130.   return (r);
  131. }
  132.  
  133. void mbox_unlock_mailbox (CONTEXT *ctx)
  134. {
  135.   if (ctx->locked)
  136.   {
  137.     fflush (ctx->fp);
  138.  
  139. #ifdef USE_SETGID
  140.     if (ctx->setgid)
  141.       SETEGID (MailGid);
  142. #endif /* USE_SETGID */
  143.  
  144.     mx_unlock_file (ctx->path, fileno (ctx->fp));
  145.     ctx->locked = 0;
  146.  
  147. #ifdef USE_SETGID
  148.     if (ctx->setgid)
  149.     {
  150.       SETEGID (UserGid);
  151.       ctx->setgid = 0;
  152.     }
  153. #endif
  154.   }
  155. }
  156.  
  157. int mmdf_parse_mailbox (CONTEXT *ctx)
  158. {
  159.   char buf[HUGE_STRING];
  160.   char return_path[LONG_STRING];
  161.   int lines;
  162.   time_t t;
  163.   long loc, tmploc;
  164.   HEADER *hdr;
  165.   struct stat sb;
  166. #ifdef NFS_ATTRIBUTE_HACK
  167.   struct utimbuf newtime;
  168. #endif
  169.  
  170.   if (stat (ctx->path, &sb) == -1)
  171.   {
  172.     mutt_perror (ctx->path);
  173.     return (-1);
  174.   }
  175.   ctx->mtime = sb.st_mtime;
  176.   ctx->size = sb.st_size;
  177.  
  178. #ifdef NFS_ATTRIBUTE_HACK
  179.   if (sb.st_mtime > sb.st_atime)
  180.   {
  181.     newtime.modtime = sb.st_mtime;
  182.     newtime.actime = time (NULL);
  183.     utime (ctx->path, &newtime);
  184.   }
  185. #endif
  186.  
  187.   buf[sizeof (buf) - 1] = 0;
  188.   FOREVER
  189.   {
  190.     if (fgets (buf, sizeof (buf) - 1, ctx->fp) == NULL)
  191.       break;
  192.  
  193.     if (strcmp (buf, MMDF_SEP) == 0)
  194.     {
  195.       loc = ftell (ctx->fp);
  196.  
  197.       if (ctx->msgcount == ctx->hdrmax)
  198.     mx_alloc_memory (ctx);
  199.       ctx->hdrs[ctx->msgcount] = hdr = mutt_new_header ();
  200.       hdr->offset = loc;
  201.       hdr->index = ctx->msgcount;
  202.  
  203.       if (fgets (buf, sizeof (buf) - 1, ctx->fp) == NULL)
  204.       {
  205.     dprint (1, (debugfile, "mmdf_parse_mailbox: unexpected EOF\n"));
  206.     break;
  207.       }
  208.  
  209.       return_path[0] = 0;
  210.       t = is_from (buf, return_path, sizeof (return_path));
  211.  
  212.       if (!t)
  213.     fseek (ctx->fp, loc, 0);
  214.       else
  215.     hdr->received = t;
  216.  
  217.       hdr->env = mutt_read_rfc822_header (ctx->fp, hdr);
  218.  
  219.       loc = ftell (ctx->fp);
  220.  
  221.       if (hdr->content->length > 0 && hdr->lines > 0)
  222.       {
  223.     tmploc = loc + hdr->content->length;
  224.  
  225.     if (tmploc < ctx->size)
  226.     {
  227.       fseek (ctx->fp, tmploc, 0);
  228.       if (fgets (buf, sizeof (buf) - 1, ctx->fp) == NULL ||
  229.           strcmp (MMDF_SEP, buf) != 0)
  230.       {
  231.         fseek (ctx->fp, loc, 0);
  232.         hdr->content->length = -1;
  233.       }
  234.     }
  235.     else
  236.       hdr->content->length = -1;
  237.       }
  238.       else
  239.     hdr->content->length = -1;
  240.  
  241.       if (hdr->content->length < 0)
  242.       {
  243.     lines = -1;
  244.     do {
  245.       loc = ftell (ctx->fp);
  246.       if (fgets (buf, sizeof (buf) - 1, ctx->fp) == NULL)
  247.         break;
  248.       lines++;
  249.     } while (strcmp (buf, MMDF_SEP) != 0);
  250.  
  251.     hdr->lines = lines;
  252.     hdr->content->length = loc - hdr->content->offset;
  253.       }
  254.  
  255.       if (!hdr->env->return_path && return_path[0])
  256.     rfc822_parse_adrlist (&hdr->env->return_path, return_path, "@");
  257.  
  258.       if (!hdr->env->from)
  259.     hdr->env->from = rfc822_cpy_adr (hdr->env->return_path);
  260.  
  261.       mx_update_context (ctx);
  262.     }
  263.     else
  264.     {
  265.       dprint (1, (debugfile, "mmdf_parse_mailbox: corrupt mailbox!\n"));
  266.       mutt_error ("Mailbox is corrupt!");
  267.       return (-1);
  268.     }
  269.   }
  270.  
  271.   return 0;
  272. }
  273.  
  274. /* Note that this function is also called when new mail is appended to the
  275.  * currently open folder, and NOT just when the mailbox is initially read.
  276.  *
  277.  * NOTE: it is assumed that the mailbox being read has been locked before
  278.  * this routine gets called.  Strange things could happen if it's not!
  279.  */
  280. int mbox_parse_mailbox (CONTEXT *ctx)
  281. {
  282.   struct stat sb;
  283.   char buf[HUGE_STRING], return_path[STRING];
  284.   HEADER *curhdr;
  285.   time_t t;
  286.   int count = 0, lines = 0;
  287.   long loc;
  288. #ifdef NFS_ATTRIBUTE_HACK
  289.   struct utimbuf newtime;
  290. #endif
  291.  
  292.   /* Save information about the folder at the time we opened it. */
  293.   if (stat (ctx->path, &sb) == -1)
  294.   {
  295.     mutt_perror (ctx->path);
  296.     return (-1);
  297.   }
  298.  
  299.   ctx->size = sb.st_size;
  300.   ctx->mtime = sb.st_mtime;
  301.  
  302. #ifdef NFS_ATTRIBUTE_HACK
  303.   if (sb.st_mtime > sb.st_atime)
  304.   {
  305.     newtime.modtime = sb.st_mtime;
  306.     newtime.actime = time (NULL);
  307.     utime (ctx->path, &newtime);
  308.   }
  309. #endif
  310.  
  311.   if (!ctx->readonly)
  312.     ctx->readonly = access (ctx->path, W_OK) ? 1 : 0;
  313.  
  314.   loc = ftell (ctx->fp);
  315.   while (fgets (buf, LONG_STRING, ctx->fp) != NULL)
  316.   {
  317.     if ((t = is_from (buf, return_path, sizeof (return_path))))
  318.     {
  319.       /* Save the Content-Length of the previous message */
  320.       if (count > 0)
  321.       {
  322. #define PREV ctx->hdrs[ctx->msgcount-1]
  323.  
  324.     if (PREV->content->length < 0)
  325.     {
  326.       PREV->content->length = loc - PREV->content->offset - 1;
  327.       if (PREV->content->length < 0)
  328.         PREV->content->length = 0;
  329.     }
  330.     if (!PREV->lines)
  331.       PREV->lines = lines ? lines - 1 : 0;
  332.       }
  333.  
  334.       count++;
  335.  
  336.       if (!ctx->quiet && ReadInc && ((count % ReadInc == 0) || count == 1))
  337.     mutt_message ("Reading %s... %d (%d%%)", ctx->path, count,
  338.               ftell (ctx->fp) / (ctx->size / 100 + 1));
  339.  
  340.       if (ctx->msgcount == ctx->hdrmax)
  341.     mx_alloc_memory (ctx);
  342.       
  343.       curhdr = ctx->hdrs[ctx->msgcount] = mutt_new_header ();
  344.       curhdr->received = t;
  345.       curhdr->offset = loc;
  346.       curhdr->index = ctx->msgcount;
  347.     
  348.       curhdr->env = mutt_read_rfc822_header (ctx->fp, curhdr);
  349.  
  350.       /* if we know how long this message is, either just skip over the body,
  351.        * or if we don't know how many lines there are, count them now (this will
  352.        * save time by not having to search for the next message marker).
  353.        */
  354.       if (curhdr->content->length > 0)
  355.       {
  356.     long tmploc;
  357.